<?php


namespace App\Controller\Api;


use App\Model\Enum\PayTypeEnum;
use App\Service\Dispatch\ChannelDispatchService;
use App\Service\RiskCheck\ChannelRiskCheckService;
use App\Service\RiskCheck\GlobalRiskCheckService;
use App\Service\RiskCheck\MchRiskCheckService;
use App\Service\RiskCheck\MchWhiteRiskCheckService;
use App\Service\RiskCheck\SuspiciousRiskCheckService;
use App\Utils\CustomUtils;
use App\Utils\DateUtils;
use App\Utils\RedisUtils;
use Co\Redis;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Di\Container;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\PostMapping;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\Arr;

/**
 * Class CheckController
 *
 * @package App\Controller\Api
 * @Controller(prefix="/api/check")
 */
class CheckController extends BaseController {


    /**
     * @var \Psr\Log\LoggerInterface
     */
    protected $logger;

    /**
     * @Inject()
     * @var MchWhiteRiskCheckService
     */
    protected $MchWhiteRiskCheckService;


    /**
     * @Inject()
     * @var GlobalRiskCheckService
     */
    protected $GlobalRiskCheckService;

    /**
     * @Inject()
     * @var MchRiskCheckService
     */
    protected $MchRiskCheckService;

    /**
     * @Inject()
     * @var ChannelDispatchService
     */
    protected $ChannelDispatchService;

    /**
     * @Inject()
     * @var ChannelRiskCheckService
     */
    protected $ChannelRiskCheckService;

    /**
     * @Inject()
     * @var SuspiciousRiskCheckService
     */
    protected $SuspiciousRiskCheckService;

    public function __construct (LoggerFactory $loggerFactory) {
        // 第一个参数对应日志的 name, 第二个参数对应 config/autoload/logger.php 内的 key
        $this->logger = $loggerFactory->get('log', 'default');
    }

    /**
     * @param RequestInterface $request
     * @PostMapping(path="riskAndDispatch")
     *
     * @return array
     */
    public function riskAndDispatch (RequestInterface $request) {

        // 请求参数示例
        // $data = [
        //    'mchNo'     => '',
        //    'amount'    => '', // 交易金额
        //    'currency'  => '', // 交易币种
        //    'bankTransList'   => [
        //        [
        //            'channelNo'         => '', // 通道编号
        //            'bankCurrency'      => '', // 银行交易币种
        //            'bankTransAmount'   => '', // 银行交易金额
        //        ]
        //    ],
        //    'riskParam' => [
        //        // 需要进行风控校验参数
        //    ],
        // ];

        CustomUtils::xzxDebug("请求参数", $request->post());

        $this->_validOrFail($request->post(), [
            'mchNo'         => 'required',
            'bankTransList' => 'required|array',
            'payType'       => 'required',
            'riskParam'     => 'sometimes|array',
        ]);

        $data = [
            'mchNo'            => $request->post('mchNo'),
            'mchTransAmount'   => $request->post('mchTransAmount'),
            'mchTransCurrency' => $request->post('mchTransCurrency'),
            'mchTransTime'     => $request->post('mchTransTime'),
            'payType'          => $request->post('payType'),
        ];

        // 商户号
        $mchNo = $data['mchNo'];

        // 需要风控的参数
        $riskParam = $request->post('riskParam', []);

        // 待调度通道
        $bankTransList = $request->post('bankTransList', []);

        $startTime = DateUtils::getMilliTime();

        // 返回data
        $retErr = null;

        $ret = [
            'mchNo'      => $mchNo,
            // 通道信息
            'channel'    => [],
            // 风控匹配规则
            'risk'       => [],
            // 白名单风控匹配规则
            'whiteText'  => [],
            // 可疑风控匹配规则
            'suspicious' => [],
        ];

        if ($this->_isCreditPay($data)) {
            // 只有信用卡支付才需要风控

            if (!$retErr) {
                // 商户白名单
                $re = $this->MchWhiteRiskCheckService->handle(array_merge($data, $riskParam));

                if (CustomUtils::isError($re)) {
                    $ret['whiteText'] = $re['data'];
                    $retErr           = CustomUtils::buildError($re['message'], $re['code'], $ret);
                }
            }

            if (!$retErr) {
                // 全局风控
                $re = $this->GlobalRiskCheckService->handle(array_merge($data, $riskParam));

                if (CustomUtils::isError($re)) {
                    $ret['risk'] = $re['data'];
                    $retErr      = CustomUtils::buildError($re['message'], $re['code'], $ret);
                }
            }

            if (!$retErr) {
                // 商户风控
                $re = $this->MchRiskCheckService->handle(array_merge($data, $riskParam));

                if (CustomUtils::isError($re)) {
                    $ret['risk'] = $re['data'];
                    $retErr      = CustomUtils::buildError($re['message'], $re['code'], $ret);
                }
            }
        }


        if (!$retErr) {
            // 通道调度
            $re = $this->ChannelDispatchService->handle($mchNo, $bankTransList);

            $ret['channel'] = $re['data'];

            if (CustomUtils::isError($re)) {
                $retErr = CustomUtils::buildError($re['message'], $re['code'], $ret);
            }
        }

        if ($this->_isCreditPay($data)) {

            if (!$retErr) {
                // 通道风控
                $channelNo = $ret['channel']['channelNo'];
                $re        = $this->ChannelRiskCheckService->handle([
                    'data'      => array_merge($data, $riskParam),
                    'channelNo' => $channelNo,
                ]);

                if (CustomUtils::isError($re)) {
                    $ret['risk'] = $re['data'];
                    $retErr      = CustomUtils::buildError($re['message'], $re['code'], $ret);
                }
            }

            if (!$retErr) {
                // 商户可疑风控
                $re = $this->SuspiciousRiskCheckService->handle(array_merge($data, $riskParam));

                if (CustomUtils::isError($re)) {
                    $ret['suspicious'] = $re['data'];
                    // 可疑这里的话，不认为是失败，但是会在业务系统记录这条可疑内容
                }
            }
        }

        $endTime = DateUtils::getMilliTime();

        CustomUtils::xzxDebug([
            "风控处理完成",
            sprintf("风控处理时间 %.3f s", ($endTime - $startTime) / 1000),
            "isSuccess = ".(!$retErr ? 'true' : 'false'),
            $ret,
        ]);

        if (!!$retErr) {
            return $retErr;
        }

        return CustomUtils::buildSuccess($ret);
    }

    /**
     * 当前是否信用卡支付
     *
     * @param $params array 完整的请求参数
     *
     * @return bool
     */
    protected function _isCreditPay ($params) {
        $payType = Arr::get($params, 'payType', PayTypeEnum::CREDIT);
        return $payType == PayTypeEnum::CREDIT;
    }
}
